add more stats collection to migration, prepare for NGIO fixup.
unsigned long max_memkb;
} xc_dominfo_t;
+typedef struct xc_shadow_control_stats_st
+{
+ unsigned long fault_count;
+ unsigned long dirty_count;
+ unsigned long dirty_net_count;
+ unsigned long dirty_block_count;
+} xc_shadow_control_stats_t;
+
int xc_domain_create(int xc_handle,
unsigned int mem_kb,
const char *name,
unsigned int sop,
unsigned long *dirty_bitmap,
unsigned long pages,
- unsigned long *fault_count,
- unsigned long *dirty_count);
+ xc_shadow_control_stats_t *stats);
#define XCFLAGS_VERBOSE 1
unsigned int sop,
unsigned long *dirty_bitmap,
unsigned long pages,
- unsigned long *fault_count,
- unsigned long *dirty_count)
+ xc_shadow_control_stats_t *stats )
{
int rc;
dom0_op_t op;
rc = do_dom0_op(xc_handle, &op);
- if(fault_count) *fault_count = op.u.shadow_control.fault_count;
- if(dirty_count) *dirty_count = op.u.shadow_control.dirty_count;
+ if(stats) memcpy(stats, &op.u.shadow_control.stats,
+ sizeof(xc_shadow_control_stats_t));
if ( rc == 0 )
return op.u.shadow_control.pages;
return (new->tv_sec * 1000000) + new->tv_usec;
}
-static long long tvdelta( struct timeval *new, struct timeval *old )
+static long long llgettimeofday()
+{
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ return tv_to_us(&now);
+}
+
+static long long tv_delta( struct timeval *new, struct timeval *old )
{
return ((new->tv_sec - old->tv_sec)*1000000 ) +
(new->tv_usec - old->tv_usec);
}
-static int track_cpu_usage( int xc_handle, u64 domid, int faults,
- int pages_sent, int pages_dirtied, int print )
+static int print_stats( int xc_handle, u64 domid,
+ int pages_sent, xc_shadow_control_stats_t *stats,
+ int print )
{
static struct timeval wall_last;
static long long d0_cpu_last;
long long d0_cpu_now, d0_cpu_delta;
long long d1_cpu_now, d1_cpu_delta;
-
gettimeofday(&wall_now, NULL);
d0_cpu_now = xc_domain_get_cpu_usage( xc_handle, 0 )/1000;
printf("ARRHHH!!\n");
}
- wall_delta = tvdelta(&wall_now,&wall_last)/1000;
+ wall_delta = tv_delta(&wall_now,&wall_last)/1000;
if ( wall_delta == 0 ) wall_delta = 1;
(int)((d0_cpu_delta*100)/wall_delta),
(int)((d1_cpu_delta*100)/wall_delta),
(int)((pages_sent*PAGE_SIZE*8)/(wall_delta*1000)),
- (int)((pages_dirtied*PAGE_SIZE*8)/(wall_delta*1000))
+ (int)((stats->dirty_count*PAGE_SIZE*8)/(wall_delta*1000))
);
d0_cpu_last = d0_cpu_now;
}
+static int analysis_phase( int xc_handle, u64 domid,
+ int nr_pfns, unsigned long *arr )
+{
+ long long start, now;
+ xc_shadow_control_stats_t stats;
+
+ start = llgettimeofday();
+
+ while(0)
+ {
+ int i;
+
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_CLEAN2,
+ arr, nr_pfns, NULL);
+ printf("#Flush\n");
+ for(i=0;i<100;i++)
+ {
+ usleep(10000);
+ now = llgettimeofday();
+ xc_shadow_control( xc_handle, domid,
+ DOM0_SHADOW_CONTROL_OP_PEEK,
+ NULL, 0, &stats);
+
+ printf("now= %lld faults= %ld dirty= %ld dirty_net= %ld dirty_block= %ld\n",
+ ((now-start)+500)/1000,
+ stats.fault_count, stats.dirty_count,
+ stats.dirty_net_count, stats.dirty_block_count );
+
+ }
+
+
+ }
+
+
+ return -1;
+}
+
int xc_linux_save(int xc_handle,
u64 domid,
unsigned int flags,
int live = flags & XCFLAGS_LIVE;
int debug = flags & XCFLAGS_DEBUG;
int sent_last_iter, sent_this_iter, skip_this_iter;
- unsigned long dirtied_this_iter, faults_this_iter;
/* Important tuning parameters */
int max_iters = 29; // limit us to 30 times round loop
- to skip this iteration because already dirty;
- to fixup by sending at the end if not already resent; */
unsigned long *to_send, *to_skip, *to_fix;
+
+ xc_shadow_control_stats_t stats;
int needed_to_fix = 0;
int total_sent = 0;
{
if ( xc_shadow_control( xc_handle, domid,
DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY,
- NULL, 0, NULL, NULL ) < 0 )
+ NULL, 0, NULL ) < 0 )
{
ERROR("Couldn't enable shadow mode");
goto out;
else
last_iter = 1;
+ /* calculate the power of 2 order of nr_pfns, e.g.
+ 15->4 16->4 17->5 */
+ for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
/* Setup to_send bitmap */
{
}
- /* calculate the power of 2 order of nr_pfns, e.g.
- 15->4 16->4 17->5 */
- for( i=nr_pfns-1, order_nr=0; i ; i>>=1, order_nr++ );
-
-printf("nr_pfns=%d order_nr=%d\n",nr_pfns, order_nr);
+ analysis_phase( xc_handle, domid, nr_pfns, to_skip );
/* We want zeroed memory so use calloc rather than malloc. */
pfn_type = calloc(BATCH_SIZE, sizeof(unsigned long));
goto out;
}
- track_cpu_usage( xc_handle, domid, 0, 0, 0, 0 );
+ print_stats( xc_handle, domid, 0, &stats, 0 );
/* Now write out each data page, canonicalising page tables as we go... */
if ( !last_iter &&
xc_shadow_control(xc_handle, domid,
DOM0_SHADOW_CONTROL_OP_PEEK,
- to_skip, nr_pfns, NULL, NULL) != nr_pfns )
+ to_skip, nr_pfns, NULL) != nr_pfns )
{
ERROR("Error peeking shadow bitmap");
goto out;
if ( last_iter )
{
- track_cpu_usage( xc_handle, domid, 0, sent_this_iter, 0, 1);
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
verbose_printf("Total pages sent= %d (%.2fx)\n",
total_sent, ((float)total_sent)/nr_pfns );
if ( debug && last_iter )
{
int minusone = -1;
- memset( to_send, 0xff, nr_pfns/8 );
+ memset( to_send, 0xff, (nr_pfns+8)/8 );
debug = 0;
printf("Entering debug resend-all mode\n");
if ( xc_shadow_control( xc_handle, domid,
DOM0_SHADOW_CONTROL_OP_CLEAN2,
- to_send, nr_pfns, &faults_this_iter,
- &dirtied_this_iter) != nr_pfns )
+ to_send, nr_pfns, &stats ) != nr_pfns )
{
ERROR("Error flushing shadow PT");
goto out;
sent_last_iter = sent_this_iter;
- //dirtied_this_iter = count_bits( nr_pfns, to_send );
- track_cpu_usage( xc_handle, domid, faults_this_iter,
- sent_this_iter, dirtied_this_iter, 1);
+ print_stats( xc_handle, domid, sent_this_iter, &stats, 1);
}
&dom, &op) )
return NULL;
- if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL, NULL) < 0 )
+ if ( xc_shadow_control(xc->xc_handle, dom, op, NULL, 0, NULL) < 0 )
return PyErr_SetFromErrno(xc_error);
Py_INCREF(zero);
intterupts disabled, hence we can't use the normal flush_tlb_cpu
mechanism.
-For the moment, we have a grim hace whereby the spinlock in the shadow
+For the moment, we have a grim race whereby the spinlock in the shadow
fault handler is actually a try lock, in a loop with a helper for the
tlb flush code.
__scan_shadow_table( m, TABLE_OP_FREE_L1 );
send_bitmap:
+ sc->stats.fault_count = p->mm.shadow_fault_count;
+ sc->stats.dirty_count = p->mm.shadow_dirty_count;
+ sc->stats.dirty_net_count = p->mm.shadow_dirty_net_count;
+ sc->stats.dirty_block_count = p->mm.shadow_dirty_block_count;
+
+ p->mm.shadow_fault_count = 0;
+ p->mm.shadow_dirty_count = 0;
+ p->mm.shadow_dirty_net_count = 0;
+ p->mm.shadow_dirty_block_count = 0;
+
+ sc->pages = p->tot_pages;
if( p->tot_pages > sc->pages ||
!sc->dirty_bitmap || !p->mm.shadow_dirty_bitmap )
goto out;
}
- sc->fault_count = p->mm.shadow_fault_count;
- sc->dirty_count = p->mm.shadow_dirty_count;
- p->mm.shadow_fault_count = 0;
- p->mm.shadow_dirty_count = 0;
-
- sc->pages = p->tot_pages;
#define chunk (8*1024) // do this in 1KB chunks for L1 cache
case DOM0_SHADOW_CONTROL_OP_PEEK:
{
int i;
+
+ sc->stats.fault_count = p->mm.shadow_fault_count;
+ sc->stats.dirty_count = p->mm.shadow_dirty_count;
+ sc->stats.dirty_net_count = p->mm.shadow_dirty_net_count;
+ sc->stats.dirty_block_count = p->mm.shadow_dirty_block_count;
if( p->tot_pages > sc->pages ||
!sc->dirty_bitmap || !p->mm.shadow_dirty_bitmap )
int i;
sl1pfn_info = alloc_shadow_page( ¤t->mm );
sl1pfn_info->type_and_flags = PGT_l1_page_table;
-
+
sl1pfn = sl1pfn_info - frame_table;
SH_VVLOG("4a: l1 not shadowed ( %08lx )",sl1pfn);
struct task_struct *p = frame_table[pfn].u.domain;
if( p->mm.shadow_mode == SHM_logdirty )
- mark_dirty( &p->mm, pfn );
+ if( mark_dirty( &p->mm, pfn ) )
+ p->mm.shadow_dirty_block_count++;
if ( writeable_buffer )
unsigned int shadow_page_count;
unsigned int shadow_fault_count;
unsigned int shadow_dirty_count;
+ unsigned int shadow_dirty_net_count;
+ unsigned int shadow_dirty_block_count;
/* Current LDT details. */
#define DOM0_SHADOW_CONTROL_OP_OFF 0
#define DOM0_SHADOW_CONTROL_OP_ENABLE_TEST 1
#define DOM0_SHADOW_CONTROL_OP_ENABLE_LOGDIRTY 2
+#define DOM0_SHADOW_CONTROL_OP_ENABLE_TRANSLATE 3
#define DOM0_SHADOW_CONTROL_OP_FLUSH 10 /* table ops */
#define DOM0_SHADOW_CONTROL_OP_CLEAN 11
#define DOM0_SHADOW_CONTROL_OP_PEEK 12
#define DOM0_SHADOW_CONTROL_OP_CLEAN2 13
+
+typedef struct dom0_shadow_control_stats_st
+{
+ unsigned long fault_count;
+ unsigned long dirty_count;
+ unsigned long dirty_net_count;
+ unsigned long dirty_block_count;
+} dom0_shadow_control_stats_t;
+
typedef struct dom0_shadow_control_st
{
/* IN variables. */
/* IN/OUT variables */
unsigned long pages; // size of buffer, updated with actual size
/* OUT varaibles */
- unsigned long fault_count;
- unsigned long dirty_count;
+ dom0_shadow_control_stats_t stats;
} dom0_shadow_control_t;
#define DOM0_SETDOMAINNAME 26
/* Shadow PT operation mode : shadowmode variable in mm_struct */
#define SHM_test (1) /* just run domain on shadow PTs */
#define SHM_logdirty (2) /* log pages that are dirtied */
-#define SHM_cow (3) /* copy on write all dirtied pages */
-#define SHM_translate (4) /* lookup machine pages in translation table */
+#define SHM_translate (3) /* lookup machine pages in translation table */
+//#define SHM_cow (4) /* copy on write all dirtied pages */
+
#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START)
#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT))))
/************************************************************************/
- static inline void __mark_dirty( struct mm_struct *m, unsigned int mfn )
+static inline int __mark_dirty( struct mm_struct *m, unsigned int mfn )
{
unsigned int pfn;
+ int rc = 0;
ASSERT(spin_is_locked(&m->shadow_lock));
really part of the domain's psuedo-physical memory map e.g.
the shared info frame. Nothing to do here...
*/
- if ( unlikely(pfn & 0x80000000U) ) return;
+ if ( unlikely(pfn & 0x80000000U) ) return rc;
ASSERT(m->shadow_dirty_bitmap);
if( likely(pfn<m->shadow_dirty_bitmap_size) )
{
- /* These updates occur with mm.shadow_lock held, so use
- (__) version of test_and_set */
- if( ! __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) )
- {
- m->shadow_dirty_count++;
- }
+ /* These updates occur with mm.shadow_lock held, so use
+ (__) version of test_and_set */
+ if( __test_and_set_bit( pfn, m->shadow_dirty_bitmap ) == 0 )
+ {
+ // if we set it
+ m->shadow_dirty_count++;
+ rc = 1;
+ }
}
else
{
frame_table[mfn].type_and_flags );
//show_traceX();
}
-
+
+ return rc;
}
-static inline void mark_dirty( struct mm_struct *m, unsigned int mfn )
+static inline int mark_dirty( struct mm_struct *m, unsigned int mfn )
{
+ int rc;
ASSERT(local_irq_is_enabled());
//if(spin_is_locked(&m->shadow_lock)) printk("+");
spin_lock(&m->shadow_lock);
- __mark_dirty( m, mfn );
+ rc = __mark_dirty( m, mfn );
spin_unlock(&m->shadow_lock);
+ return rc;
}
/* if in shadow mode, mark the buffer as dirty */
if( p->mm.shadow_mode == SHM_logdirty )
- mark_dirty( &p->mm, (new_page-frame_table) );
+ {
+ if( mark_dirty( &p->mm, (new_page-frame_table) ) )
+ p->mm.shadow_dirty_net_count++;
+ }
/* Updates must happen before releasing the descriptor. */
smp_wmb();
if( p->mm.shadow_mode == SHM_logdirty )
{
mark_dirty( &p->mm, rx->pte_ptr>>PAGE_SHIFT );
-#if 0
- mark_dirty( &p->mm, rx->buf_pfn ); // XXXXXXX debug
-
- {
- unsigned long * p = map_domain_mem( rx->buf_pfn<<PAGE_SHIFT );
- p[2] = 0xdeadc001;
- unmap_domain_mem(p);
- }
-#endif
-
}
/* assume the shadow page table is about to be blown away,
and that its not worth marking the buffer as dirty */